home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / UNIX / C / INDENT / LEXI.C < prev    next >
C/C++ Source or Header  |  1989-09-02  |  16KB  |  621 lines

  1. /*
  2.  * Copyright (c) 1985 Sun Microsystems, Inc.
  3.  * Copyright (c) 1980 The Regents of the University of California.
  4.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by the University of California, Berkeley, the University of Illinois,
  13.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  14.  * or Sun Microsystems may not be used to endorse or promote products
  15.  * derived from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)lexi.c    5.11 (Berkeley) 9/15/88";
  23. #endif /* not lint */
  24.  
  25. /*
  26.  * Here we have the token scanner for indent.  It scans off one token and puts
  27.  * it in the global variable "token".  It returns a code, indicating the type
  28.  * of token scanned.
  29.  */
  30.  
  31. #include "indent_globs.h"
  32. #include <ctype.h>
  33.  
  34. #define alphanum 1
  35. #define opchar 3
  36.  
  37. enum rwcodes {
  38.   rw_none,
  39.   rw_break,
  40.   rw_switch,
  41.   rw_case,
  42.   rw_struct_like, /* struct, enum, union */
  43.   rw_decl,
  44.   rw_sp_paren, /* if, while, for */
  45.   rw_sp_nparen, /* do, else */
  46.   rw_sizeof
  47.   };
  48.  
  49. struct templ {
  50.     char       *rwd;
  51.     enum rwcodes rwcode;
  52. };
  53.  
  54. struct templ *user_specials = 0;
  55. unsigned int user_specials_max, user_specials_idx;
  56.  
  57. char        chartype[128] =
  58. {                /* this is used to facilitate the decision of
  59.                  * what type (alphanumeric, operator) each
  60.                  * character is */
  61.     0, 0, 0, 0, 0, 0, 0, 0,
  62.     0, 0, 0, 0, 0, 0, 0, 0,
  63.     0, 0, 0, 0, 0, 0, 0, 0,
  64.     0, 0, 0, 0, 0, 0, 0, 0,
  65.     0, 3, 0, 0, 1, 3, 3, 0,
  66.     0, 0, 3, 3, 0, 3, 0, 3,
  67.     1, 1, 1, 1, 1, 1, 1, 1,
  68.     1, 1, 0, 0, 3, 3, 3, 3,
  69.     0, 1, 1, 1, 1, 1, 1, 1,
  70.     1, 1, 1, 1, 1, 1, 1, 1,
  71.     1, 1, 1, 1, 1, 1, 1, 1,
  72.     1, 1, 1, 0, 0, 0, 3, 1,
  73.     0, 1, 1, 1, 1, 1, 1, 1,
  74.     1, 1, 1, 1, 1, 1, 1, 1,
  75.     1, 1, 1, 1, 1, 1, 1, 1,
  76.     1, 1, 1, 0, 3, 0, 3, 0
  77. };
  78.  
  79. /* The generated perfect hash function functions that recognize the reserved words. 
  80.    C code produced by gperf version 1.8.1 (GNU C++ version) 
  81.    Command-line: gperf -c -p -t -T -g -j1 -o -K rwd -N is_reserved indent.gperf  */
  82.  
  83. #define MIN_WORD_LENGTH 2
  84. #define MAX_WORD_LENGTH 8
  85. #define MIN_HASH_VALUE 4
  86. #define MAX_HASH_VALUE 40
  87. /*
  88.    29 keywords
  89.    37 is the maximum key range
  90. */
  91.  
  92. #ifdef __GNUC__
  93. inline
  94. #endif
  95. static int
  96. hash (str, len)
  97.      register char  *str;
  98.      register int  len;
  99. {
  100.   static unsigned char hash_table[] =
  101.     {
  102.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  103.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  104.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  105.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  106.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  107.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  108.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  109.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  110.      40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
  111.      40, 40, 40, 40, 40, 40, 40, 40, 24,  9,
  112.      10,  0, 15, 20,  6,  8, 40,  0,  0, 19,
  113.       1, 16, 40, 40,  1,  0,  0, 12, 21,  4,
  114.      40, 40, 40, 40, 40, 40, 40, 40,
  115.     };
  116.   return len + hash_table[str[len - 1]] + hash_table[str[0]];
  117. }
  118.  
  119. #ifdef __GNUC__
  120. inline
  121. #endif
  122. struct templ*
  123. is_reserved  (str, len)
  124.      register char *str;
  125.      register int len;
  126. {
  127.  
  128.   static struct templ wordlist[] =
  129.     {
  130.       {"",}, {"",}, {"",}, {"",}, 
  131.       {"else",  rw_sp_nparen,},
  132.       {"short",  rw_decl,},
  133.       {"struct",  rw_struct_like,},
  134.       {"extern",  rw_decl,},
  135.       {"return",  rw_break,},
  136.       {"while",  rw_sp_paren,},
  137.       {"register",  rw_decl,},
  138.       {"int",  rw_decl,},
  139.       {"switch",  rw_switch,},
  140.       {"case",  rw_case,},
  141.       {"char",  rw_decl,},
  142.       {"static",  rw_decl,},
  143.       {"double",  rw_decl,},
  144.       {"default",  rw_case,},
  145.       {"union",  rw_struct_like,},
  146.       {"for",  rw_sp_paren,},
  147.       {"float",  rw_decl,},
  148.       {"sizeof",  rw_sizeof,},
  149.       {"typedef",  rw_decl,},
  150.       {"enum",  rw_struct_like,},
  151.       {"long",  rw_decl,},
  152.       {"if",  rw_sp_paren,},
  153.       {"global",  rw_decl,},
  154.       {"va_dcl",  rw_decl,},
  155.       {"do",  rw_sp_nparen,},
  156.       {"break",  rw_break,},
  157.       {"unsigned",  rw_decl,},
  158.       {"",}, {"",}, {"",}, {"",}, 
  159.       {"void",  rw_decl,},
  160.       {"",}, {"",}, {"",}, {"",}, 
  161.       {"goto",  rw_break,},
  162.     };
  163.  
  164.   if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
  165.     {
  166.       register int key = hash (str, len);
  167.  
  168.       if (key <= MAX_HASH_VALUE && key >= MIN_HASH_VALUE)
  169.         {
  170.           register char *s = wordlist[key].rwd;
  171.  
  172.           if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
  173.             return &wordlist[key];
  174.         }
  175.     }
  176.   return 0;
  177. }
  178.  
  179. enum codes
  180. lexi()
  181. {
  182.     /* used to walk through the token */
  183.     char *tok;
  184.     
  185.     int         unary_delim;    /* this is set to 1 if the current token
  186.                  * 
  187.                  * forces a following operator to be unary */
  188.     static enum codes last_code;    /* the last token type returned */
  189.     static int  l_struct;    /* set to 1 if the last token was 'struct' */
  190.     enum codes  code;        /* internal code to be returned */
  191.     char        qchar;        /* the delimiter character for a string */
  192.  
  193.     unary_delim = false;
  194.     parser_state_tos->col_1 = parser_state_tos->last_nl;    /* tell world that this token started in
  195.                  * column 1 iff the last thing scanned was nl */
  196.     parser_state_tos->last_nl = false;
  197.  
  198.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
  199.     parser_state_tos->col_1 = false;    /* leading blanks imply token is not in column
  200.                  * 1 */
  201.     if (++buf_ptr >= buf_end)
  202.         fill_buffer();
  203.     }
  204.  
  205.     token = buf_ptr;
  206.  
  207.     /* Scan an alphanumeric token */
  208.     if (chartype[*buf_ptr] == alphanum || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) {
  209.     /*
  210.      * we have a character or number
  211.      */
  212.     register char *j;    /* used for searching thru list of
  213.                  * 
  214.                  * reserved words */
  215.     register struct templ *p;
  216.  
  217.     if (isdigit(*buf_ptr) || buf_ptr[0] == '.' && isdigit(buf_ptr[1])) {
  218.         int         seendot = 0,
  219.                     seenexp = 0;
  220.         if (*buf_ptr == '0' &&
  221.             (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) {
  222.             buf_ptr += 2;
  223.         while (isxdigit(*buf_ptr))
  224.             buf_ptr++;
  225.         }
  226.         else
  227.         while (1) {
  228.             if (*buf_ptr == '.')
  229.             if (seendot)
  230.                 break;
  231.             else
  232.                 seendot++;
  233.             buf_ptr++;
  234.             if (!isdigit(*buf_ptr) && *buf_ptr != '.')
  235.             if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
  236.                 break;
  237.             else {
  238.                 seenexp++;
  239.                 seendot++;
  240.                 buf_ptr++;
  241.                 if (*buf_ptr == '+' || *buf_ptr == '-')
  242.                 buf_ptr++;
  243.             }
  244.         }
  245.         if (*buf_ptr == 'L' || *buf_ptr == 'l')
  246.         buf_ptr++;
  247.     }
  248.     else
  249.         while (chartype[*buf_ptr] == alphanum) {    /* copy it over */
  250.         buf_ptr++;
  251.         if (buf_ptr >= buf_end)
  252.             fill_buffer();
  253.         }
  254.     token_end = buf_ptr;
  255.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
  256.         if (++buf_ptr >= buf_end)
  257.         fill_buffer();
  258.     }
  259.     parser_state_tos->its_a_keyword = false;
  260.     parser_state_tos->sizeof_keyword = false;
  261.     if (l_struct) {        /* if last token was 'struct', then this token
  262.                  * should be treated as a declaration */
  263.         l_struct = false;
  264.         last_code = ident;
  265.         parser_state_tos->last_u_d = true;
  266.         return (decl);
  267.     }
  268.     parser_state_tos->last_u_d = false;    /* Operator after indentifier is binary */
  269.     last_code = ident;    /* Remember that this is the code we will
  270.                  * return */
  271.  
  272.     /* Check whether the token is a reserved word.  Use perfect hashing... */
  273.         p = is_reserved (token, token_end - token);
  274.  
  275.     if (p) {        /* we have a keyword */
  276.     found_keyword:
  277.         parser_state_tos->its_a_keyword = true;
  278.         parser_state_tos->last_u_d = true;
  279.         switch (p->rwcode) {
  280.         case rw_switch:        /* it is a switch */
  281.         return (swstmt);
  282.         case rw_case:        /* a case or default */
  283.         return (casestmt);
  284.  
  285.         case rw_struct_like:        /* a "struct" */
  286.         if (parser_state_tos->p_l_follow)
  287.             break;    /* inside parens: cast */
  288.         l_struct = true;
  289.  
  290.         /*
  291.          * Next time around, we will want to know that we have had a
  292.          * 'struct'
  293.          */
  294.         case rw_decl:        /* one of the declaration keywords */
  295.         if (parser_state_tos->p_l_follow) {
  296.             parser_state_tos->cast_mask |= 1 << parser_state_tos->p_l_follow;
  297.             break;    /* inside parens: cast */
  298.         }
  299.         last_code = decl;
  300.         return (decl);
  301.  
  302.         case rw_sp_paren:        /* if, while, for */
  303.         return (sp_paren);
  304.  
  305.         case rw_sp_nparen:        /* do, else */
  306.         return (sp_nparen);
  307.  
  308.         case rw_sizeof:
  309.         parser_state_tos->sizeof_keyword = true;
  310.         default:        /* all others are treated like any other
  311.                  * identifier */
  312.         return (ident);
  313.         }            /* end of switch */
  314.     }            /* end of if (found_it) */
  315.     if (*buf_ptr == '(' && parser_state_tos->tos <= 1 && parser_state_tos->ind_level == 0) {
  316.         register char *tp = buf_ptr;
  317.         while (tp < buf_end)
  318.         if (*tp++ == ')' && (*tp == ';' || *tp == ','))
  319.             goto not_proc;
  320.         parser_state_tos->procname = token;
  321.         parser_state_tos->procname_end = token_end;
  322.         parser_state_tos->in_parameter_declaration = 1;
  323.     not_proc:;
  324.     }
  325.     /*
  326.      * The following hack attempts to guess whether or not the current
  327.      * token is in fact a declaration keyword -- one that has been
  328.      * typedefd
  329.      */
  330.     if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_')
  331.         && !parser_state_tos->p_l_follow
  332.             && !parser_state_tos->block_init
  333.         && (parser_state_tos->last_token == rparen || parser_state_tos->last_token == semicolon ||
  334.             parser_state_tos->last_token == decl ||
  335.             parser_state_tos->last_token == lbrace || parser_state_tos->last_token == rbrace)) {
  336.         parser_state_tos->its_a_keyword = true;
  337.         parser_state_tos->last_u_d = true;
  338.         last_code = decl;
  339.         return decl;
  340.     }
  341.     if (last_code == decl)    /* if this is a declared variable, then
  342.                  * following sign is unary */
  343.         parser_state_tos->last_u_d = true;    /* will make "int a -1" work */
  344.     last_code = ident;
  345.     return (ident);        /* the ident is not in the list */
  346.     }                /* end of procesing for alpanum character */
  347.     /* Scan a non-alphanumeric token */
  348.  
  349.     /* If it is not a one character token, token_end will get changed
  350.        later.  */
  351.     token_end = buf_ptr + 1;
  352.  
  353.     if (++buf_ptr >= buf_end)
  354.     fill_buffer();
  355.  
  356.     switch (*token) {
  357.     case '\n':
  358.     unary_delim = parser_state_tos->last_u_d;
  359.     parser_state_tos->last_nl = true;    /* remember that we just had a newline */
  360.     code = (had_eof ? code_eof : newline);
  361.  
  362.     /*
  363.      * if data has been exausted, the newline is a dummy, and we should
  364.      * return code to stop
  365.      */
  366.     break;
  367.  
  368.     case '\'':            /* start of quoted character */
  369.     case '"':            /* start of string */
  370.     qchar = *token;
  371.  
  372.     /* Find out how big the literal is so we can set token_end.  */
  373.     
  374.     /* Invariant:  before loop test buf_ptr points to the next */
  375.     /* character that we have not yet checked. */
  376.     while (*buf_ptr != qchar && *buf_ptr != 0 && *buf_ptr != '\n')
  377.       {
  378.         if (*buf_ptr == '\\')
  379.           {
  380.         buf_ptr++;
  381.         if (buf_ptr >= buf_end)
  382.           fill_buffer ();
  383.         if (*buf_ptr == '\n')
  384.           ++line_no;
  385.         if (*buf_ptr == 0)
  386.           break;
  387.           }
  388.         buf_ptr++;
  389.         if (buf_ptr >= buf_end)
  390.           fill_buffer ();
  391.       }
  392.     if (*buf_ptr == '\n' || *buf_ptr == 0)
  393.       {
  394.         diag (1,
  395.           qchar == '\''
  396.             ? "Unterminated character constant"
  397.             : "Unterminated string constant"
  398.          );
  399.       }
  400.     else
  401.       {
  402.         /* Advance over end quote char.  */
  403.         buf_ptr++;
  404.         if (buf_ptr >= buf_end)
  405.           fill_buffer ();
  406.       }
  407.  
  408.     code = ident;
  409.     break;
  410.  
  411.     case ('('):
  412.     case ('['):
  413.     unary_delim = true;
  414.     code = lparen;
  415.     break;
  416.  
  417.     case (')'):
  418.     case (']'):
  419.     code = rparen;
  420.     break;
  421.  
  422.     case '#':
  423.     unary_delim = parser_state_tos->last_u_d;
  424.     code = preesc;
  425.     break;
  426.  
  427.     case '?':
  428.     unary_delim = true;
  429.     code = question;
  430.     break;
  431.  
  432.     case (':'):
  433.     code = colon;
  434.     unary_delim = true;
  435.     break;
  436.  
  437.     case (';'):
  438.     unary_delim = true;
  439.     code = semicolon;
  440.     break;
  441.  
  442.     case ('{'):
  443.     unary_delim = true;
  444.  
  445.     /* This check is made in the code for '='.  No one who writes
  446.        initializers without '=' these days deserves to have indent
  447.        work on their code (besides which, uncommenting this would
  448.        screw up anything which assumes that parser_state_tos->block_init really
  449.        means you are in an initializer.  */
  450.     /*
  451.      * if (parser_state_tos->in_or_st) parser_state_tos->block_init = 1;
  452.      */
  453.  
  454.     /* The following neat hack causes the braces in structure
  455.        initializations to be treated as parentheses, thus causing
  456.        initializations to line up correctly, e.g.
  457.        struct foo bar =
  458.        {{a,
  459.          b,
  460.          c},
  461.         {1,
  462.          2}};
  463.        If lparen is returned, token can be used to distinguish
  464.        between '{' and '(' where necessary.  */
  465.  
  466.     code = parser_state_tos->block_init ? lparen : lbrace;
  467.     break;
  468.  
  469.     case ('}'):
  470.     unary_delim = true;
  471.     /* The following neat hack is explained under '{' above.  */
  472.     code = parser_state_tos->block_init ? rparen : rbrace;
  473.  
  474.     break;
  475.  
  476.     case 014:            /* a form feed */
  477.     unary_delim = parser_state_tos->last_u_d;
  478.     parser_state_tos->last_nl = true;    /* remember this so we can set 'parser_state_tos->col_1'
  479.                  * right */
  480.     code = form_feed;
  481.     break;
  482.  
  483.     case (','):
  484.     unary_delim = true;
  485.     code = comma;
  486.     break;
  487.  
  488.     case '.':
  489.     unary_delim = false;
  490.     code = period;
  491.     break;
  492.  
  493.     case '-':
  494.     case '+':            /* check for -, +, --, ++ */
  495.     code = (parser_state_tos->last_u_d ? unary_op : binary_op);
  496.     unary_delim = true;
  497.  
  498.     if (*buf_ptr == token[0]) {
  499.         /* check for doubled character */
  500.         buf_ptr++;
  501.         /* buffer overflow will be checked at end of loop */
  502.         if (last_code == ident || last_code == rparen) {
  503.         code = (parser_state_tos->last_u_d ? unary_op : postop);
  504.         /* check for following ++ or -- */
  505.         unary_delim = false;
  506.         }
  507.     }
  508.     else if (*buf_ptr == '=')
  509.         /* check for operator += */
  510.         buf_ptr++;
  511.     else if (*buf_ptr == '>') {
  512.         /* check for operator -> */
  513.         buf_ptr++;
  514.         if (!pointer_as_binop) {
  515.         unary_delim = false;
  516.         code = unary_op;
  517.         parser_state_tos->want_blank = false;
  518.         }
  519.     }
  520.     break;            /* buffer overflow will be checked at end of
  521.                  * switch */
  522.  
  523.     case '=':
  524.     if (parser_state_tos->in_or_st)
  525.         parser_state_tos->block_init = 1;
  526.  
  527.     if (*buf_ptr == '=') /* == */
  528.         buf_ptr++;
  529.  
  530.     code = binary_op;
  531.     unary_delim = true;
  532.     break;
  533.     /* can drop thru!!! */
  534.  
  535.     case '>':
  536.     case '<':
  537.     case '!':            /* ops like <, <<, <=, !=, etc */
  538.     if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
  539.         if (++buf_ptr >= buf_end)
  540.         fill_buffer();
  541.     }
  542.  
  543.     code = (parser_state_tos->last_u_d ? unary_op : binary_op);
  544.     unary_delim = true;
  545.     break;
  546.  
  547.     default:
  548.     if (token[0] == '/' && *buf_ptr == '*') {
  549.         /* it is start of comment */
  550.  
  551.         if (++buf_ptr >= buf_end)
  552.         fill_buffer();
  553.  
  554.         code = comment;
  555.         unary_delim = parser_state_tos->last_u_d;
  556.         break;
  557.     }
  558.     while (*(buf_ptr - 1) == *buf_ptr || *buf_ptr == '=') {
  559.         /*
  560.          * handle ||, &&, etc, and also things as in int *****i
  561.          */
  562.         if (++buf_ptr >= buf_end)
  563.         fill_buffer();
  564.     }
  565.     code = (parser_state_tos->last_u_d ? unary_op : binary_op);
  566.     unary_delim = true;
  567.  
  568.  
  569.     }                /* end of switch */
  570.     if (code != newline) {
  571.     l_struct = false;
  572.     last_code = code;
  573.     }
  574.     token_end = buf_ptr;
  575.     if (buf_ptr >= buf_end)    /* check for input buffer empty */
  576.     fill_buffer();
  577.     parser_state_tos->last_u_d = unary_delim;
  578.  
  579.     return (code);
  580. }
  581.  
  582. /*
  583.  * Add the given keyword to the keyword table, using val as the keyword type
  584.  */
  585. addkey(key, val)
  586.     char       *key;
  587.      enum rwcodes val;
  588. {
  589.     register struct templ *p;
  590.  
  591.     /* Check to see whether key is a reserved word or not. */
  592.     if (is_reserved (key, strlen (key)) != 0)
  593.       return;
  594.  
  595.     if (user_specials == 0)
  596.       {
  597.     user_specials = (struct templ *) xmalloc (5 * sizeof (struct templ));
  598.     if (user_specials == 0)
  599.       {
  600.         fputs ("indent: out of memory\n", stderr);
  601.         exit (1);
  602.       }
  603.     user_specials_max = 5;
  604.     user_specials_idx = 0;
  605.       }
  606.     else if (user_specials_idx == user_specials_max)
  607.       {
  608.     user_specials_max += 5;
  609.     user_specials = (struct templ *) xrealloc ((char *) user_specials,
  610.                           user_specials_max
  611.                           * sizeof (struct templ));
  612.       }
  613.     p = &user_specials[user_specials_idx++];
  614.  
  615.     p->rwd = key;
  616.     p->rwcode = val;
  617.     p[1].rwd = 0;
  618.     p[1].rwcode = rw_none;
  619.     return;
  620. }
  621.